"""
RedFire框架 - 统一安全管理模块

提供统一的认证、授权、密码处理等安全功能
支持JWT、OAuth2、密码哈希等标准安全机制
"""

import hashlib
import secrets
import jwt
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, List, Union
from passlib.context import CryptContext
from passlib.hash import bcrypt
from fastapi import HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, validator
import re


class TokenData(BaseModel):
    """JWT Token数据模型"""
    user_id: Optional[Union[str, int]] = None
    username: Optional[str] = None
    email: Optional[str] = None
    roles: List[str] = []
    scopes: List[str] = []
    exp: Optional[datetime] = None
    iat: Optional[datetime] = None


class SecurityConfig(BaseModel):
    """安全配置模型"""
    # JWT配置
    jwt_secret_key: str = "your-secret-key-change-in-production"
    jwt_algorithm: str = "HS256"
    jwt_access_token_expire_minutes: int = 30
    jwt_refresh_token_expire_days: int = 7
    
    # 密码配置
    password_min_length: int = 8
    password_require_uppercase: bool = True
    password_require_lowercase: bool = True
    password_require_digit: bool = True
    password_require_special: bool = True
    
    # 其他安全配置
    email_regex: str = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    phone_regex: str = r'^1[3-9]\d{9}$'  # 中国手机号
    username_regex: str = r'^[a-zA-Z0-9_]{3,20}$'
    max_login_attempts: int = 5
    lockout_duration_minutes: int = 15


class PasswordManager:
    """密码管理器 - 提供密码哈希和验证功能"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
        self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
    
    def hash_password(self, password: str) -> str:
        """
        哈希密码
        
        Args:
            password: 明文密码
            
        Returns:
            str: 哈希后的密码
        """
        # 调试信息
        print(f"🔍 hash_password 输入: type={type(password)}, len={len(password)}, bytes_len={len(password.encode('utf-8'))}")
        print(f"🔍 password[:50]={password[:50]}")
        
        # bcrypt限制：密码不能超过72字节
        # 确保传入的是原始密码而不是已哈希的密码
        if len(password.encode('utf-8')) > 72:
            raise ValueError(f"Password is too long ({len(password.encode('utf-8'))} bytes). Must be 72 bytes or less.")
        
        return self.pwd_context.hash(password)
    
    def verify_password(self, plain_password: str, hashed_password: str) -> bool:
        """
        验证密码
        
        Args:
            plain_password: 明文密码
            hashed_password: 哈希密码
            
        Returns:
            bool: 验证结果
        """
        return self.pwd_context.verify(plain_password, hashed_password)
    
    def validate_password_strength(self, password: str) -> Dict[str, Any]:
        """
        验证密码强度
        
        Args:
            password: 待验证的密码
            
        Returns:
            Dict[str, Any]: 验证结果
        """
        errors = []
        
        if len(password) < self.config.password_min_length:
            errors.append(f"密码长度至少{self.config.password_min_length}位")
        
        if self.config.password_require_uppercase and not any(c.isupper() for c in password):
            errors.append("密码必须包含大写字母")
        
        if self.config.password_require_lowercase and not any(c.islower() for c in password):
            errors.append("密码必须包含小写字母")
        
        if self.config.password_require_digit and not any(c.isdigit() for c in password):
            errors.append("密码必须包含数字")
        
        if self.config.password_require_special and not any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in password):
            errors.append("密码必须包含特殊字符")
        
        return {
            "is_valid": len(errors) == 0,
            "errors": errors,
            "strength_score": self._calculate_strength_score(password)
        }
    
    def _calculate_strength_score(self, password: str) -> int:
        """计算密码强度分数 (0-100)"""
        score = 0
        
        # 长度加分
        if len(password) >= 8:
            score += 25
        if len(password) >= 12:
            score += 25
        
        # 字符类型加分
        if any(c.isupper() for c in password):
            score += 15
        if any(c.islower() for c in password):
            score += 15
        if any(c.isdigit() for c in password):
            score += 10
        if any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in password):
            score += 10
        
        return min(score, 100)


class JWTManager:
    """JWT管理器 - 提供JWT token的生成和验证功能"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
    
    def create_access_token(self, data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
        """
        创建访问token
        
        Args:
            data: token数据
            expires_delta: 过期时间增量
            
        Returns:
            str: JWT token
        """
        to_encode = data.copy()
        
        if expires_delta:
            expire = datetime.utcnow() + expires_delta
        else:
            expire = datetime.utcnow() + timedelta(minutes=self.config.jwt_access_token_expire_minutes)
        
        to_encode.update({"exp": expire, "iat": datetime.utcnow()})
        encoded_jwt = jwt.encode(to_encode, self.config.jwt_secret_key, algorithm=self.config.jwt_algorithm)
        return encoded_jwt
    
    def create_refresh_token(self, data: Dict[str, Any]) -> str:
        """
        创建刷新token
        
        Args:
            data: token数据
            
        Returns:
            str: 刷新token
        """
        to_encode = data.copy()
        expire = datetime.utcnow() + timedelta(days=self.config.jwt_refresh_token_expire_days)
        to_encode.update({"exp": expire, "iat": datetime.utcnow(), "type": "refresh"})
        
        encoded_jwt = jwt.encode(to_encode, self.config.jwt_secret_key, algorithm=self.config.jwt_algorithm)
        return encoded_jwt
    
    def verify_token(self, token: str) -> TokenData:
        """
        验证token
        
        Args:
            token: JWT token
            
        Returns:
            TokenData: 解析后的token数据
            
        Raises:
            HTTPException: token无效时抛出异常
        """
        try:
            payload = jwt.decode(token, self.config.jwt_secret_key, algorithms=[self.config.jwt_algorithm])
            
            return TokenData(
                user_id=payload.get("user_id"),
                username=payload.get("username"),
                email=payload.get("email"),
                roles=payload.get("roles", []),
                scopes=payload.get("scopes", []),
                exp=datetime.fromtimestamp(payload.get("exp", 0)),
                iat=datetime.fromtimestamp(payload.get("iat", 0))
            )
        except jwt.ExpiredSignatureError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Token已过期",
                headers={"WWW-Authenticate": "Bearer"},
            )
        except jwt.PyJWTError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Token无效",
                headers={"WWW-Authenticate": "Bearer"},
            )
    
    def refresh_token(self, refresh_token: str) -> str:
        """
        刷新访问token
        
        Args:
            refresh_token: 刷新token
            
        Returns:
            str: 新的访问token
        """
        token_data = self.verify_token(refresh_token)
        
        # 创建新的访问token
        new_token_data = {
            "user_id": token_data.user_id,
            "username": token_data.username,
            "email": token_data.email,
            "roles": token_data.roles,
            "scopes": token_data.scopes
        }
        
        return self.create_access_token(new_token_data)


class SecurityService:
    """
    统一安全服务 - 整合所有安全功能的主服务类
    
    这是框架提供的核心安全服务，各微服务通过依赖注入使用
    """
    
    def __init__(self, config: Optional[Union[SecurityConfig, Dict[str, Any]]] = None):
        if isinstance(config, dict):
            self.config = SecurityConfig(**config)
        else:
            self.config = config or SecurityConfig()
        self.password_manager = PasswordManager(self.config)
        self.jwt_manager = JWTManager(self.config)
        self.bearer_scheme = HTTPBearer()
    
    # 密码相关方法
    def hash_password(self, password: str) -> str:
        """哈希密码"""
        return self.password_manager.hash_password(password)
    
    def verify_password(self, plain_password: str, hashed_password: str) -> bool:
        """验证密码"""
        return self.password_manager.verify_password(plain_password, hashed_password)
    
    def validate_password_strength(self, password: str) -> Dict[str, Any]:
        """验证密码强度"""
        return self.password_manager.validate_password_strength(password)
    
    # JWT相关方法
    def create_access_token(self, user_data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
        """创建访问token"""
        return self.jwt_manager.create_access_token(user_data, expires_delta)
    
    def create_refresh_token(self, user_data: Dict[str, Any]) -> str:
        """创建刷新token"""
        return self.jwt_manager.create_refresh_token(user_data)
    
    def verify_token(self, token: str) -> TokenData:
        """验证token"""
        return self.jwt_manager.verify_token(token)
    
    def refresh_access_token(self, refresh_token: str) -> str:
        """刷新访问token"""
        return self.jwt_manager.refresh_token(refresh_token)
    
    # 工具方法
    def generate_api_key(self, length: int = 32) -> str:
        """
        生成API密钥
        
        Args:
            length: 密钥长度
            
        Returns:
            str: 生成的API密钥
        """
        return secrets.token_urlsafe(length)


# =====================================================
# 验证器类 - 为了兼容测试代码
# =====================================================

class EmailValidator:
    """邮箱验证器"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
    
    def validate(self, email: str) -> bool:
        """验证邮箱格式"""
        if not email:
            return False
        return bool(re.match(self.config.email_regex, email))


class PasswordValidator:
    """密码验证器"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
        self.password_manager = PasswordManager(config)
    
    def validate(self, password: str) -> bool:
        """验证密码强度"""
        result = self.password_manager.validate_password_strength(password)
        return result["is_valid"]
    
    def get_validation_errors(self, password: str) -> List[str]:
        """获取密码验证错误"""
        result = self.password_manager.validate_password_strength(password)
        return result["errors"]


class PhoneNumberValidator:
    """手机号验证器"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
    
    def validate(self, phone: str) -> bool:
        """验证手机号格式"""
        if not phone:
            return False
        return bool(re.match(self.config.phone_regex, phone))


class UsernameValidator:
    """用户名验证器"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
    
    def validate(self, username: str) -> bool:
        """验证用户名格式"""
        if not username:
            return False
        return bool(re.match(self.config.username_regex, username))


class ValidationService:
    """综合验证服务"""
    
    def __init__(self, config: Optional[SecurityConfig] = None):
        self.config = config or SecurityConfig()
        self.email_validator = EmailValidator(config)
        self.password_validator = PasswordValidator(config)
        self.phone_validator = PhoneNumberValidator(config)
        self.username_validator = UsernameValidator(config)
    
    def validate_email(self, email: str) -> bool:
        """验证邮箱"""
        return self.email_validator.validate(email)
    
    def validate_password(self, password: str) -> bool:
        """验证密码"""
        return self.password_validator.validate(password)
    
    def validate_phone(self, phone: str) -> bool:
        """验证手机号"""
        return self.phone_validator.validate(phone)
    
    def validate_username(self, username: str) -> bool:
        """验证用户名"""
        return self.username_validator.validate(username)


# 全局实例和便捷函数已废弃，统一使用DI容器管理
# _security_service: Optional[SecurityService] = None
# def get_security_service(...)
# def verify_token(...)
# def get_jwt_manager(...)


__all__ = [
    "SecurityConfig",
    "TokenData",
    "PasswordManager",
    "JWTManager",
    "SecurityService",
    "EmailValidator",
    "PasswordValidator", 
    "PhoneNumberValidator",
    "UsernameValidator",
    "ValidationService",
    # "get_security_service",
    # "verify_token",
    # "get_jwt_manager",
    "validate_email",
    "validate_password",
    "validate_phone", 
    "validate_username",
]
